//    Copyright (C) Kherty.  All rights reserved.
#region

using System;
using System.Collections.Generic;
using System.Diagnostics;
#if !SILVERLIGHT
using System.Diagnostics.Contracts;
using System.Drawing;
using System.Drawing.Imaging;
#endif
using System.IO;
using System.IO.Packaging;
using System.Threading;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using OpenLS.Core.Serialization;
using OpenLS.Drawing.Serialization;

#endregion

namespace OpenLS.Drawing
{
    /// <summary>
    /// Data used to define the pixels of a picture
    /// </summary>
    public class Blip : IOfficeXmlSerializable
    {
        /// <summary>
        /// Initializes a new instance of the Blip class.
        /// </summary>
        public Blip()
        {
            
        }

        public Blip(byte [] data, string extension)
        {
            this._blipData = new BlipData(data, extension);
        }
        delegate void SimpleDelegate();
        private List<Effect> _effects = new List<Effect>();
       // private string _extension;

        //\\byte[] _data;
        private string _link;
        //private byte[] _rawData;
        //private BitmapSource _source;
        private string uri;
        private BlipData _blipData;
        private OfficeArtExtensionList extLst;
        private BlipCompression _cstate;

        public List<Effect> Effects
        {
            get { return _effects; }
            internal set { _effects = value; }
        }

        public BitmapSource Source
        {
            get
            {
                if (_blipData == null || _blipData.Source == null)
                {
                    BitmapImage img = null;
                    if (img == null)
                    {
                        if (_blipData == null || _blipData._rawData == null)
                        {
                            Debug.WriteLine("no raw data");
                            return null;
                        }

                        img = new BitmapImage();
                        img.BeginInit();
                        var legacyImage  = Image.FromStream(new MemoryStream(_blipData._rawData));
                        Stream streamSource = new MemoryStream();
                        legacyImage.Save(streamSource, ImageFormat.Png);
                        streamSource.Position = 0;
                        img.StreamSource = streamSource;
                        img.EndInit();
                    }
                    Debug.WriteLine("Setting source, Thread = " + Thread.CurrentThread.ManagedThreadId + " " + Thread.CurrentThread);
                    _blipData.Source = img;
                    
                }
                return _blipData.Source;
            }
            set
            {
                if (value == null)
                    _blipData = null;
                else
                {


                    _blipData = new BlipData(value);
                }
                //_source = value;
                //\\ object f = BitmapFrame.Create(Source);

                //\\_source = BitmapFrame.Create(Source);
            }
        }

        public byte [] Bytes
        {
            get
            {
                if (_blipData != null)
                {
                    return _blipData.GetBytes();
                }
                return null;
            }
        }
        public string Extension
        {
            get
            {
                if (_blipData != null && _blipData._extension != null)
                {
                    Contract.Assert(_blipData._extension != null);
                    return _blipData._extension;
                }
                if (Source != null)
                {
                    var encoder = _blipData.GetEncoder();
                    if (encoder != null)
                        return encoder.CodecInfo.FileExtensions.Split(',')[0];
                    return ".png";//\\check this
                }
                return ".png"; //\\hmm
            }
        }

        #region IOfficeXmlSerializable Members

        void IOfficeXmlSerializable.ReadXml(ReadContext context)
        {
            using (var c = context.Read(DrawingConstants.DrawingNamespace + "blip"))
            {
                var embed = c.GetOptionalString(OfficeConstants.RelationshipNamespace +  "embed");
                _link = c.GetOptionalString(OfficeConstants.RelationshipNamespace +  "link");
                this._cstate = c.GetOptionalEnum<BlipCompression>("cstate", BlipCompression.None);
                if (embed != null)
                {
                    var rel = context.Part.GetRelationship(embed);
                    try
                    {

                        // if (rel.TargetUri.OriginalString == "NULL")
                            // Contract.Assert(false);
                        var blipPart =
                            context.Part.Package.GetPart(PackUriHelper.ResolvePartUri(context.Part.Uri, rel.TargetUri));
                        var dictionary = context.GetData <Dictionary<Uri, object>>();
                        if (dictionary != null && dictionary.ContainsKey(blipPart.Uri))
                        {
                            _blipData = (BlipData) dictionary[blipPart.Uri];
                        }
                        else
                        {

                            this._blipData = new BlipData();
                            _blipData._extension = Path.GetExtension(blipPart.Uri.ToString());
                            uri = blipPart.Uri.ToString();
                            //\\ blipPart.ContentType;
                            using (var stream = blipPart.GetStream())
                            {
                                Dispatcher dispatcher = context.GetData<Dispatcher>();
                                if (dispatcher != null)
                                {
                                    dispatcher.Invoke (DispatcherPriority.Send, new SimpleDelegate(() => _blipData.ReadStream(stream,
                                                                                            Path.GetExtension(
                                                                                                blipPart.Uri.ToString()))));
                                }
                                else
                                {
                                    _blipData.ReadStream(stream, Path.GetExtension(blipPart.Uri.ToString()));

                                }
                            }
                            if (dictionary != null)
                                dictionary.Add(blipPart.Uri, _blipData);
                        }
                    }
                    catch{}

                }
                else
                {
                    //\\ handle link
                }
                context.PassAttributes();
                var effect = Effect.ReadEffect(c);
                while (effect != null)
                {
                    Effects.Add(effect);
                    effect = Effect.ReadEffect(c);
                }
                this.extLst = c.ReadOptionalElement<OfficeArtExtensionList>("extLst");
            }
        }

        void IOfficeXmlSerializable.WriteXml(WriteContext context)
        {
            using (var c = context.Write(DrawingConstants.DrawingNamespace + "blip"))
            {
                c.SetOptionalEnum("cstate", _cstate, BlipCompression.None);
                if (_blipData != null)
                    WriteBlipData(context, c);
                foreach (var ee in Effects)
                    c.WriteElement(ee);
                c.WriteOptionalElement(extLst);
            }
        }

        private void WriteBlipData(WriteContext context, WriteContext c)
        {
            var dictionary = c.GetData<Dictionary<object, Uri>>();
            if (dictionary != null && dictionary.ContainsKey(_blipData))
            {
                Uri uri = dictionary[_blipData];
                var rel = c.Part.CreateRelationship(uri, TargetMode.Internal,
                                                    OfficeConstants.ImageRelationshipType);
                c.SetString(OfficeConstants.RelationshipNamespace + "embed", rel.Id);

            }
            else
            {
                var uri = _blipData.WriteBlipData(context, c);
                var rel = c.Part.CreateRelationship(uri, TargetMode.Internal,
                                                    OfficeConstants.ImageRelationshipType);
                c.SetString(OfficeConstants.RelationshipNamespace + "embed", rel.Id);
                if (dictionary != null)
                    dictionary.Add(_blipData, uri);
          
            }
        }

        #endregion
    }
}